package com.zhouwr.common.message;

import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

@AllArgsConstructor
@Getter
public enum MessageType {
    //上报设备属性
    REPORT_PROPERTY(ReportPropertyMessage::new),
    //下行调用功能
    INVOKE_FUNCTION(FunctionInvokeMessage::new),
    //事件消息
    EVENT(DeviceEventMessage::new),
    //设备上线
    ONLINE(DeviceOnlineMessage::new),
    //设备离线
    OFFLINE(DeviceOfflineMessage::new),
    //注册
    REGISTER(DeviceRegisterMessage::new),
    //注销
    UN_REGISTER(DeviceUnRegisterMessage::new),
    //平台主动断开连接
    DISCONNECT(DisconnectDeviceMessage::new),
    /* 设备心跳 */
    HEART(DeviceHeartMessage::new),
    //未知消息
    UNKNOWN(null);

    final Supplier<? extends Message> message;

    private static final Map<String, MessageType> mapping;

    static {
        mapping = new HashMap<>();
        for (MessageType value : values()) {
            mapping.put(value.name().toLowerCase(), value);
            mapping.put(value.name().toUpperCase(), value);
        }
    }

    @SuppressWarnings("all")
    public <T extends Message> T convert(Map<String, Object> map) {
        if (message != null) {
            T msg = (T) message.get();
            msg.fromJson(new JSONObject(map));
            return msg;
        }
        return null;
    }

    public static MessageType of(String messageName) {
        return Optional.ofNullable(mapping.get(messageName))
                .orElseThrow();
    }

    public static MessageType of(Map<String, Object> map) {
        Object msgType = map.get("messageType");
        if (msgType instanceof MessageType) {
            return (MessageType) msgType;
        } else if (msgType instanceof String) {
            return of(((String) msgType));
        }

        if (map.containsKey("event")) {
            return EVENT;
        }

        if (map.containsKey("functionId")) {
            return map.containsKey("inputs") ? INVOKE_FUNCTION : REPORT_PROPERTY;
        }
        if (map.containsKey("properties")) {
            Object properties = map.get("properties");
            return properties instanceof Collection ? INVOKE_FUNCTION : REPORT_PROPERTY;
        }
        return UNKNOWN;
    }
}
